Skip to content

gh-160561: Close the duplicated descriptor when fromfd() is rejected - #160579

Open
lumenyr wants to merge 3 commits into
python:mainfrom
lumenyr:gh-160561-fromfd-leak
Open

lumenyr wants to merge 3 commits into
python:mainfrom
lumenyr:gh-160561-fromfd-leak

Conversation

@lumenyr

@lumenyr lumenyr commented Oct 24, 2026 •

Copy link
Copy Markdown

socket.fromfd() duplicates the descriptor and then hands it to the constructor. If the constructor rejects its arguments, the duplicate has no owner and is never closed.

fd = sock.fileno()
for _ in range(3):
    try:
        socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM, 1 << 100)
    except OverflowError:
        pass

That leaks 3 descriptors; with the change, 0. A valid call still returns a working socket and the descriptor count is unchanged.

The test counts /proc/self/fd before and after one rejected call, so it is skipped where /proc is absent. It passes on this branch and fails against unmodified Lib/socket.py with AssertionError: 7 != 6.

./python -m unittest test.test_socket.BasicTCPTest.testFromFdInvalidArgsDoesNotLeak is OK, and test_socket is green on the free-threading debug build (run=755, skipped=50).

NEWS entry included. No behaviour change on the success path.

@lumenyr
lumenyr force-pushed the gh-160561-fromfd-leak branch from 06cb5dc to c7af374 Compare October 24, 2026 09:36
Comment thread Lib/socket.py Outdated
Comment on lines +578 to +580
# socket() rejected the arguments; the dup()'d descriptor would
# otherwise leak, since nothing holds a reference to it.
close(nfd)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that the comment is useful.

Suggested change
# socket() rejected the arguments; the dup()'d descriptor would
# otherwise leak, since nothing holds a reference to it.
close(nfd)
close(nfd)

Comment thread Lib/socket.py Outdated
return socket(family, type, proto, nfd)
try:
return socket(family, type, proto, nfd)
except BaseException:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO a bare except is better here, since we just re-raise the exception later.

Suggested change
except BaseException:
except:

Comment thread Lib/test/test_socket.py

def _testFromFdInvalidArgsDoesNotLeak(self):
pass

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use os_helper.fd_count() which works on all platforms. I suggest a shorter test name and more flat code to trigger errors:

Suggested change
def testFromFdError(self):
# Make sure that the fromfd() duplicated socket is closed on error.
# In debug mode, Python test suite checks for file descriptor leaks.
fd = self.cli_conn.fileno()
fd_count_before = os_helper.fd_count()
with self.assertRaises(TypeError):
socket.fromfd(fd, "not-a-valid-family", socket.SOCK_STREAM)
with self.assertRaises(TypeError):
socket.fromfd(fd, socket.AF_UNIX, "not-a-valid-type")
with self.assertRaises(OverflowError):
socket.fromfd(fd, socket.AF_UNIX, 1 << 100)
self.assertEqual(os_helper.fd_count(), fd_count_before)
def _testFromFdError(self):
pass

Remove the code comment and use a bare except, as requested. Rename
the test to testFromFdError, flatten it and use os_helper.fd_count()
so the descriptor count works on all platforms.
@python-cla-bot

Copy link
Copy Markdown

The following commit authors need to sign the Contributor License Agreement:

CLA not signed

@vstinner

Copy link
Copy Markdown
Member

@lumenyr: Please sign the Python CLA: see #160579 (comment) comment.

@vstinner vstinner added needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes labels Oct 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review needs backport to 3.14 bugs and security fixes needs backport to 3.15 bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants